# -*- python -*-
# ex: set syntax=python:

# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# It has one job: define a dictionary named BuildmasterConfig. This
# dictionary has a variety of keys to control different aspects of the
# buildmaster. They are documented in docs/config.xhtml .

from buildbot.changes import gitpoller
from buildbot.status.mail import MailNotifier
from buildbot import scheduler

from common import chromium_utils

from master import master_utils
from master import slaves_list
from master.factory import annotator_factory
from master.factory import drmemory_factory

import config
import master_site_config
ActiveMaster = master_site_config.DynamoRIO

MASTER_HOST = ActiveMaster.master_host
MAIL_NOTIFIER = ActiveMaster.is_production_host
MASTER_PORT = ActiveMaster.master_port

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c, require_dbconfig=ActiveMaster.is_production_host)

# 'slavePortnum' defines the TCP port to listen on. This must match the value
# configured into the buildslaves (with their --master option)
c['slavePortnum'] = ActiveMaster.slave_port

slaves = slaves_list.SlavesList('slaves.cfg', 'DynamoRIO')


####### CHANGESOURCES

if ActiveMaster.is_production_host:
  from buildbot.changes.gitpoller import GitPoller
  drm_poller = GitPoller(repourl=drmemory_factory.dr_giturl,
                         workdir="gitpoller",
                         gitbin=chromium_utils.GIT_BIN,
                         pollinterval=60,
  )
  c['change_source'] = [ drm_poller ]

####### SCHEDULERS

# We have bots for these versions of Windows.
WINDOWS_VERSIONS = ['xp', '7', '8']

# This is a list of bots that run DR's pre-commit suite.  We want to turn on
# email notification when the suite is red, but we're not there yet.
SUITE_BOTS = []
for os_version in WINDOWS_VERSIONS:
  SUITE_BOTS.append('win-%s-dr' % os_version)
# We only have one Linux bot currently.
SUITE_BOTS.append('linux-dr')

PACKAGE_BOTS = ['win-dr-package', 'linux-dr-package']

NIGHTLY_BOTS = ['%s-nightly' % bot for bot in SUITE_BOTS]

c['schedulers'] = []
c['schedulers'].append(scheduler.Scheduler(
                           name='all',
                           branch='master',
                           treeStableTimer=60,
                           builderNames=SUITE_BOTS + PACKAGE_BOTS))
c['schedulers'].append(scheduler.Periodic(
                           name='periodic_stable',
                           branch='master',
                           periodicBuildTimer=6*60*60,  # Every 6 hours
                           builderNames=['linux-v8-dr']))
c['schedulers'].append(scheduler.Nightly(
                           name='dr-nightly',
                           branch='master',
                           # CTest will always forcibly update the source to the
                           # revision at 4 AM EST as specified in
                           # dynamorio/CTestConfig.cmake.  Make sure the build
                           # start time is *after* 4 AM EST in the current day.
                           # The master is on Pacific time subject to DST.  2 AM
                           # PT should always be after 4 AM EST, regardless of
                           # daylight savings.
                           hour=2, minute=0,
                           builderNames=NIGHTLY_BOTS))

####### BUILDERS

m_annotator = annotator_factory.AnnotatorFactory()

f_suite = drmemory_factory.DynamoRIOSuiteFactory
f_nightly = drmemory_factory.DynamoRIONightlyFactory
f_package = drmemory_factory.DynamoRIOPackageFactory

c['builders'] = []

## Suite bots
for os_version in WINDOWS_VERSIONS:
  c['builders'].append({'name': 'win-%s-dr' % os_version,
                        'factory': f_suite(os='win', os_version=os_version)})

# Stale processes aren't as much of a problem on Linux as on Windows, so we turn
# off auto_reboot for now.
c['builders'].append({'name': 'linux-dr',
                      'factory': f_suite(os='linux'),
                      'auto_reboot': False,
                      })

## Package bots

c['builders'].extend([
    {
        'name': 'linux-dr-package',
        'factory': f_package(os='linux'),
        'auto_reboot': False,
    },
    {
        'name': 'win-dr-package',
        'factory': f_package(os='win', os_version='7'),
    },
])

## Nightly bots

for os_version in WINDOWS_VERSIONS:
  f = f_nightly(os='win', os_version=os_version)
  c['builders'].append({'name': 'win-%s-dr-nightly' % os_version,
                        'factory': f})

c['builders'].append({'name': 'linux-dr-nightly',
                      'factory': f_nightly(os='linux'),
                      'auto_reboot': False,
                      })

c['builders'].append({'name': 'linux-v8-dr',
                      'factory': m_annotator.BaseFactory('v8'),
                      'auto_reboot': False,
                      })

####### BUILDSLAVES

for builder in c['builders']:
  builder['slavenames'] = slaves.GetSlavesName(builder=builder['name'])

# The 'slaves' list defines the set of allowable buildslaves. List all the
# slaves registered to a builder. Remove dupes.
c['slaves'] = master_utils.AutoSetupSlaves(c['builders'],
                                           config.Master.GetBotPassword())

# Make sure everything works together.
master_utils.VerifySetup(c, slaves)


####### STATUS TARGETS

# These guys are green and send email on failure.
STABLE_BUILDERS = ['win-7-dr', 'linux-dr', 'win-dr-package', 'linux-dr-package']

# Adds common status and tools to this master.

# The 'buildbotURL' string should point to the location where the buildbot's
# internal web server (usually the html.Waterfall page) is visible. This
# typically uses the port number set in the Waterfall 'status' entry, but
# with an externally-visible host name which the buildbot cannot figure out
# without some help.

# Must come before AutoSetupMaster().
c['buildbotURL'] = ActiveMaster.buildbot_url

master_utils.AutoSetupMaster(c, ActiveMaster)

# Satisfy the mock testing which will check whether command strings have
# unset properties but won't run the steps that set those properties:
c['properties']['pkg_buildnum'] = '<unset>'

c['status'].append(MailNotifier(fromaddr='timurrrr+drm+buildbot@google.com',
                   lookup='gmail.com', # add @gmail.com if "@" is not in the commiter's ID
                   extraRecipients=['dynamorio-devs@googlegroups.com'],
                   builders=STABLE_BUILDERS,
                   mode='problem'))

# Keep last build logs, the default is too low.
c['buildHorizon'] = 1000
c['logHorizon'] = 500
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 200
# Must be at least 1x the number of builds listed in console.
c['buildCacheSize'] = 60


####### DEBUGGING OPTIONS

# if you set 'debugPassword', then you can connect to the buildmaster with
# the diagnostic tool in contrib/debugclient.py . From this tool, you can
# manually force builds and inject changes, which may be useful for testing
# your buildmaster without actually commiting changes to your repository (or
# before you have a functioning 'sources' set up). The debug tool uses the
# same port number as the slaves do: 'slavePortnum'.

#c['debugPassword'] = 'debugpassword'

# if you set 'manhole', you can ssh into the buildmaster and get an
# interactive python shell, which may be useful for debugging buildbot
# internals. It is probably only useful for buildbot developers. You can also
# use an authorized_keys file, or plain telnet.
#from buildbot import manhole
#c['manhole'] = manhole.PasswordManhole('tcp:9999:interface=127.0.0.1',
#                                       'admin', 'password')


####### PROJECT IDENTITY

# the 'projectName' string will be used to describe the project that this
# buildbot is working on. For example, it is used as the title of the
# waterfall HTML page. The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.

c['projectName'] = ActiveMaster.project_name
c['projectURL'] = config.Master.project_url
